package com.sheliduan.itlearning.common.controller.interceptor;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.sheliduan.itlearning.common.aspect.AuthAccess;
import com.sheliduan.itlearning.common.domain.dos.UserDO;
import com.sheliduan.itlearning.common.domain.mapper.UserMapper;
import com.sheliduan.itlearning.common.enums.ErrorCodeEnum;
import com.sheliduan.itlearning.common.exception.BizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author: 断舍离
 * @date: 2025/2/3 10:14
 * @description: Token 拦截器
 **/
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private UserMapper userMapper;

    /*
    * controller方法执行前进行拦截
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 检查拦截的方法是否加了@AuthAccess, 若加了可以直接放行, 不用进行token认证
        if(handler instanceof HandlerMethod) {
            // 获得方法上的自定义注解
            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
            if(annotation != null) {
                return true;
            }
        }
        // 从http请求头中拿到token
        String token = request.getHeader("token");
        // 若没有拿到token, 说明是未登录状态, 抛异常
        if (token == null) {
            throw new BizException(ErrorCodeEnum.NOT_LOGIN);
        }
        String userId;
        try {
            // 使用JWT包对token解码, 拿到我们存储的用户id
            // Audience是JWT包下的一个集合属性, 我们可以存储多个
            // 这里我们只存储了一个,所以get(0)就可以获取到
            userId = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException e) {
            // 若出现格式错误、签名不匹配、token过期同样判断为未登录
            throw new BizException(ErrorCodeEnum.NOT_LOGIN);
        }
        // 从数据库查出对应用户
        UserDO user = userMapper.selectById(Integer.valueOf(userId));
        if(user == null) {
            throw new BizException(ErrorCodeEnum.NOT_LOGIN);
        }
        // 通过用户密码加密, 生成验证器
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();

        try {
            // 验证token
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e){
            throw new BizException(ErrorCodeEnum.NOT_LOGIN);
        }
        // 上述校验都通过后，说明是登录状态, 拦截放行
        return true;
    }
}
